// 11.1 类的属性与方法
// 在面向对象语言中，类是一种面向对象计算机编程语言的构造，是创建对象的蓝图，描述了所创建的对象共同的属性和方法。

// 在 TypeScript 中，我们可以通过 Class 关键字来定义一个类：

//  ​
//  class Greeter {
//    // 静态属性
//    static cname: string = "Greeter";
//    // 成员属性
//    greeting: string;
//  ​
//    // 构造函数 - 执行初始化操作
//    constructor(message: string) {
//      this.greeting = message;
//    }
//  ​
//    // 静态方法
//    static getClassName() {
//      return "Class name is Greeter";
//    }
//  ​
//    // 成员方法
//    greet() {
//      return "Hello, " + this.greeting;
//    }
//  }
//  ​
//  let greeter = new Greeter("world");
// 那么成员属性与静态属性，成员方法与静态方法有什么区别呢？这里无需过多解释，我们直接看一下以下编译生成的 ES5 代码：

//  ​
//  "use strict";
//  var Greeter = /** @class */ (function () {
//      // 构造函数 - 执行初始化操作
//      function Greeter(message) {
//          this.greeting = message;
//      }
//      // 静态方法
//      Greeter.getClassName = function () {
//          return "Class name is Greeter";
//      };
//      // 成员方法
//      Greeter.prototype.greet = function () {
//          return "Hello, " + this.greeting;
//      };
//      // 静态属性
//      Greeter.cname = "Greeter";
//      return Greeter;
//  }());
//  var greeter = new Greeter("world");
// 11.2 访问器

// 在 TypeScript 中，我们可以通过 getter 和 setter 方法来实现数据的封装和有效性校验，防止出现异常数据。

//  ​
//  let passcode = "Hello TypeScript";
//  ​
//  class Employee {
//    private _fullName: string;
//  ​
//    get fullName(): string {
//      return this._fullName;
//    }
//  ​
//    set fullName(newName: string) {
//      if (passcode && passcode == "Hello TypeScript") {
//        this._fullName = newName;
//      } else {
//        console.log("Error: Unauthorized update of employee!");
//      }
//    }
//  }
//  ​
//  let employee = new Employee();
//  employee.fullName = "Semlinker";
//  if (employee.fullName) {
//    console.log(employee.fullName);
//  }
// 11.3 类的继承

// 继承 (Inheritance) 是一种联结类与类的层次模型。指的是一个类（称为子类、子接口）继承另外的一个类（称为父类、父接口）的功能，并可以增加它自己的新功能的能力，继承是类与类或者接口与接口之间最常见的关系。

// 继承是一种 ref="https://zh.wikipedia.org/wiki/Is-a">is-a 关系：


// 在 TypeScript 中，我们可以通过 extends 关键字来实现继承：

//  ​
//  class Animal {
//    name: string;
   
//    constructor(theName: string) {
//      this.name = theName;
//    }
   
//    move(distanceInMeters: number = 0) {
//      console.log(`${this.name} moved ${distanceInMeters}m.`);
//    }
//  }
//  ​
//  class Snake extends Animal {
//    constructor(name: string) {
//      super(name);
//    }
   
//    move(distanceInMeters = 5) {
//      console.log("Slithering...");
//      super.move(distanceInMeters);
//    }
//  }
//  ​
//  let sam = new Snake("Sammy the Python");
//  sam.move();
// 11.4 ECMAScript 私有字段
// 在 TypeScript 3.8 版本就开始支持ECMAScript 私有字段，使用方式如下：

//  ​
//  class Person {
//    #name: string;
//  ​
//    constructor(name: string) {
//      this.#name = name;
//    }
//  ​
//    greet() {
//      console.log(`Hello, my name is ${this.#name}!`);
//    }
//  }
//  ​
//  let semlinker = new Person("Semlinker");
//  ​
//  semlinker.#name;
//  //     ~~~~~
//  // Property '#name' is not accessible outside class 'Person'
//  // because it has a private identifier.
// 与常规属性（甚至使用 private 修饰符声明的属性）不同，私有字段要牢记以下规则：

// 私有字段以 # 字符开头，有时我们称之为私有名称；
// 每个私有字段名称都唯一地限定于其包含的类；
// 不能在私有字段上使用 TypeScript 可访问性修饰符（如 public 或 private）；
// 私有字段不能在包含的类之外访问，甚至不能被检测到。




//   function deepClone(obj, cache = new WeakMap()) {
//     // 检查缓存中是否已经存在该对象，避免循环引用导致的栈溢出
//     if (cache.has(obj)) {
//       return cache.get(obj);
//     }
  
//     let clone;
//     const Constructor = obj.constructor;
  
//     switch (Constructor) {
//       case Object:
//         clone = Object.create(Object.getPrototypeOf(obj));
//         break;
//       case Array:
//         clone = [];
//         break;
//       default:
//         clone = new Constructor();
//     }
  
//     // 缓存原始对象和克隆对象，以便后续处理循环引用
//     cache.set(obj, clone);
//     cache.set(clone, obj);
  
//     // 处理对象和数组的属性
//     for (let key in obj) {
//       const value = obj[key];
//       clone[key] = typeof value === "object" ? deepClone(value, cache) : value;
//     }
  
//     // 处理原型链上的属性
//     const prototype = Object.getPrototypeOf(obj);
//     if (prototype !== null) {
//       clone.__proto__ = deepClone(prototype, cache);
//     }
  
//     return clone;
//   }

//   const obj = {
//     name: "Alice",
//     age: 25,
//     address: {
//       city: "Shanghai",
//       district: "Pudong"
//     }
//   };
  
//   const clonedObj = deepClone(obj);
//   console.log(clonedObj); // {name: "Alice", age: 25, address: {city: "Shanghai", district: "Pudong"}}
  